/**
 * 
 */
package edu.gtcfla.km.repositories.hibernate4;

import java.io.Serializable;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.hibernate.Query;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Repository;
import org.vsg.biz.BusinessEntityFactory;
import org.vsg.biz.utils.RepoInjectManager;
import org.vsg.common.orm.hibernate4.HibernateSessionManager;
import org.vsg.common.page.PaginationManager;

import edu.gtcfla.km.Knowledge;
import edu.gtcfla.km.UploadFile;
import edu.gtcfla.km.model.UploadFileD;
import edu.gtcfla.km.repositories.UploadFileRepo;

/**
 * @author Bill Vison
 *
 */
@Repository
public class UploadFileRepoImpl<T extends UploadFile, ID extends Serializable>  implements UploadFileRepo<T, ID> {

	
	@Autowired
	private ApplicationContext ctx;
	
	@Autowired	
	private BusinessEntityFactory entityFactory;
	
	@Autowired(required=false)
	private PaginationManager paginationManager;

	private HibernateSessionManager sessionManager;
	

	private static final Logger logger = LoggerFactory.getLogger(UploadFileRepoImpl.class);

	@Autowired
	public void setSessionFactory(SessionFactory sessionFactory) {
		sessionManager = new HibernateSessionManager(sessionFactory);
	}	
	
	@Override
	public void save(T entity) {
		// TODO Auto-generated method stub
		Session session = sessionManager.getSession();
		
		if (entity instanceof UploadFileD) {
			UploadFileD domainD = (UploadFileD)entity;

			ID id = (ID)session.save(session.merge(domainD) );
	
 			RepoInjectManager injectManager = new RepoInjectManager(ctx);		
			injectManager.injectSingle(entity);		
		}		
	}


	@Override
	public void update(T entity) {
		// TODO Auto-generated method stub
		Session session = sessionManager.getSession();
		
		if (entity instanceof UploadFileD) {
			UploadFileD domainD = (UploadFileD)entity;

			session.update(session.merge(domainD));
	
			RepoInjectManager injectManager = new RepoInjectManager(ctx);		
			injectManager.injectSingle(entity);		
		}		
	}


	@Override
	public T findOne(ID primaryKey) {
		// TODO Auto-generated method stub
		Session session = sessionManager.getSession();
		
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.title , entity.shared , entity.releasedDate , entity.releasedUserId , ");
		query.append("entity.fileName , entity.ext , entity.contentType ");


		query.append("from ").append(UploadFileD.class.getName()).append(" as entity ");
		query.append("left join entity.categoryD as cate ");

		
		query.append("where entity.id = :pk ");

		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		hql.setString("pk", primaryKey.toString());


		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		

		RepoInjectManager injectManager = new RepoInjectManager(ctx);	
		UploadFileD entity = null;
		if (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			entity = new UploadFileD();
			int i = 0;
			
			entity.setId( (String)fields[i++] );
			entity.setTitle( (String)fields[i++] );
			entity.setShared((Short)fields[i++] );
			entity.setReleasedDate( (Date)fields[i++] );
			entity.setReleasedUserId( (String)fields[i++] );
			
			entity.setFileName( (String)fields[i++] );
			entity.setExt(  (String)fields[i++]  );
			entity.setContentType(  (String)fields[i++]  );
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );

		}
		return (T)entity;

	}


	@Override
	public Iterable<T> findAll() {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public Long count() {
		// TODO Auto-generated method stub
		return null;
	}


	@Override
	public Iterable<T> findAllByCate(String cateId, String type) {
		
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.title , entity.shared , entity.releasedDate , entity.releasedUserId , ");
		query.append("entity.fileName , entity.ext , entity.contentType ");


		query.append("from ").append(UploadFileD.class.getName()).append(" as entity ");
		query.append("left join entity.categoryD as cate ");
		
		if (type != null) {
			query.append("left join entity.bindingFileFormats as bingFileFormat ");
		}
		
		query.append("where cate.id = :cateId ");
		
		if (type != null) {
			query.append("and bingFileFormat.id = :bingFileFormatId ");
		}

		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		hql.setString("cateId", cateId);
		if ( type != null) {
			hql.setString("bingFileFormatId", type);
		}


		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		Set<T>  result = new LinkedHashSet<T>();
		RepoInjectManager injectManager = new RepoInjectManager(ctx);	
		while (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			UploadFileD entity = new UploadFileD();
			int i = 0;
			
			entity.setId( (String)fields[i++] );
			entity.setTitle( (String)fields[i++] );
			entity.setShared((Short)fields[i++] );
			entity.setReleasedDate( (Date)fields[i++] );
			entity.setReleasedUserId( (String)fields[i++] );
			
			entity.setFileName( (String)fields[i++] );
			entity.setExt(  (String)fields[i++]  );
			entity.setContentType(  (String)fields[i++]  );
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			result.add( (T)entity);

		}
		return result;
	}

	@Override
	public void bindingAttacthmentToDoc(UploadFile uploadFile, Knowledge km) {
		// TODO Auto-generated method stub
		Set<UploadFile>  attachments =  km.getAttachments();
		
		if (attachments == null) {
			attachments = new LinkedHashSet<UploadFile>();
		}
		
		
		Session session = sessionManager.getSession();		
		uploadFile.setColligation( km);

		session.update(session.merge(uploadFile));		

	}

	@Override
	public Map<String, T> findAllMapByIds(Collection<String> ids) {
		// TODO Auto-generated method stub
		
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.title , entity.shared , entity.releasedDate , entity.releasedUserId , ");
		query.append("entity.fileName , entity.ext , entity.contentType ");

		query.append("from ").append(UploadFileD.class.getName()).append(" as entity ");
		
		query.append("where entity.id in (:ids) ");

		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		if (ids.isEmpty()) {
			ids.add( "" );
		}
		hql.setParameterList("ids", ids);


		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		Map<String , T>  result = new LinkedHashMap<String ,T>();
		RepoInjectManager injectManager = new RepoInjectManager(ctx);
		
		while (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			UploadFileD entity = new UploadFileD();
			int i = 0;
			
			entity.setId( (String)fields[i++] );
			entity.setTitle( (String)fields[i++] );
			entity.setShared((Short)fields[i++] );
			entity.setReleasedDate( (Date)fields[i++] );
			entity.setReleasedUserId( (String)fields[i++] );
			entity.setFileName( (String)fields[i++] );
			entity.setExt(  (String)fields[i++]  );
			entity.setContentType(  (String)fields[i++]  );
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			result.put( entity.getId() , (T)entity);

		}
		return result;
	}

	@Override
	public Iterable<T> findAllByKnowledge(String docId) {
		// TODO Auto-generated method stub
		
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.title , entity.shared , entity.releasedDate , entity.releasedUserId , ");
		query.append("entity.fileName , entity.ext , entity.contentType ");
		query.append("from ").append(UploadFileD.class.getName()).append(" as entity ");
		query.append("left join entity.knowledgeD as know ");
		query.append("where know.id = :docId ");

		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		hql.setString("docId", docId);

		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		Set<T>  result = new LinkedHashSet<T>();
		RepoInjectManager injectManager = new RepoInjectManager(ctx);
		
		while (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			UploadFileD entity = new UploadFileD();
			int i = 0;
			
			entity.setId( (String)fields[i++] );
			entity.setTitle( (String)fields[i++] );
			entity.setShared((Short)fields[i++] );
			entity.setReleasedDate( (Date)fields[i++] );
			entity.setReleasedUserId( (String)fields[i++] );
			entity.setFileName( (String)fields[i++] );
			entity.setExt(  (String)fields[i++]  );
			entity.setContentType(  (String)fields[i++]  );
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			result.add( (T)entity);

		}
		
		return result;
	}

	@Override
	public Iterable<T> findAllByKnowledgeAndFileFormat(String docId,
			String fileFormat) {
		// TODO Auto-generated method stub
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.title , entity.shared , entity.releasedDate , entity.releasedUserId , ");
		query.append("entity.fileName , entity.ext , entity.contentType ");

		query.append("from ").append(UploadFileD.class.getName()).append(" as entity ");
		query.append("left join entity.knowledgeD as know ");

		if (fileFormat != null) {
			query.append("left join entity.bindingFileFormats as bingFileFormat ");
		}		
		
		query.append("where know.id = :docId ");

		if (fileFormat != null) {
			query.append("and bingFileFormat.id = :bingFileFormatId ");
		}

		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		hql.setString("docId", docId);
		if ( fileFormat != null) {
			hql.setString("bingFileFormatId", fileFormat);
		}

		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		Set<T>  result = new LinkedHashSet<T>();
		RepoInjectManager injectManager = new RepoInjectManager(ctx);
		
		while (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			UploadFileD entity = new UploadFileD();
			int i = 0;
			
			entity.setId( (String)fields[i++] );
			entity.setTitle( (String)fields[i++] );
			entity.setShared((Short)fields[i++] );
			entity.setReleasedDate( (Date)fields[i++] );
			entity.setReleasedUserId( (String)fields[i++] );
			entity.setFileName( (String)fields[i++] );
			entity.setExt(  (String)fields[i++]  );
			entity.setContentType(  (String)fields[i++]  );
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			result.add( (T)entity);

		}
		
		return result;
	}

	@Override
	public void delete(T entity) {
		Session sess = sessionManager.getSession();
		sess.delete( entity );
		
	}

	@Override
	public Iterable<T> findAllByCateAndFileFormat(Set<String> categoryIds,
			String currentUserId, String userGroupId, String fileFormat) {
		// TODO Auto-generated method stub
		StringBuilder query = new StringBuilder("select ");
		query.append("entity.id , entity.title , entity.shared , entity.releasedDate , entity.releasedUserId , ");
		query.append("entity.fileName , entity.ext , entity.contentType ");


		query.append("from ").append(UploadFileD.class.getName()).append(" as entity ");
		query.append("left join entity.categoryD as cate ");
		
		if (fileFormat != null) {
			query.append("left join entity.bindingFileFormats as bingFileFormat ");
		}
		
		query.append("where cate.id in :cateIds ");
		query.append(" and ( ");
		query.append(" (entity.shared = 0 and entity.releasedUserId = :userId) ");
		if (userGroupId != null) {
			query.append(" OR (entity.shared = 1 and entity.userGroupId = :userGroupId) ");
		}
		query.append(" OR entity.shared = 2 ");
		query.append(") ") ;
		
		
		if (fileFormat != null) {
			query.append("and bingFileFormat.id = :bingFileFormatId ");
		}

		logger.debug("query : " + query.toString());
		
		Session sess = sessionManager.getSession();
		
		Query hql = sess.createQuery( query.toString() );
		hql.setParameterList("cateIds", categoryIds);
		hql.setParameter("userId", currentUserId );
		if (userGroupId != null) {
			hql.setParameter("userGroupId", userGroupId );
		}

		if ( fileFormat != null) {
			hql.setString("bingFileFormatId", fileFormat);
		}


		Iterator<Object[]> iterRes = (Iterator<Object[]>) hql.iterate();
		
		Set<T>  result = new LinkedHashSet<T>();
		RepoInjectManager injectManager = new RepoInjectManager(ctx);	
		while (iterRes.hasNext()) {
			Object[] fields = iterRes.next();
			
			UploadFileD entity = new UploadFileD();
			int i = 0;
			
			entity.setId( (String)fields[i++] );
			entity.setTitle( (String)fields[i++] );
			entity.setShared((Short)fields[i++] );
			entity.setReleasedDate( (Date)fields[i++] );
			entity.setReleasedUserId( (String)fields[i++] );
			
			entity.setFileName( (String)fields[i++] );
			entity.setExt(  (String)fields[i++]  );
			entity.setContentType(  (String)fields[i++]  );
			
			// --- convert to dto ----
			injectManager.injectSingle( entity );
			result.add( (T)entity);

		}
		return result;
	}



	
	

	
}
